package splab.ufcg.edu.br.trace.indexer;

import java.io.File;

import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrServer;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;

import splab.ufcg.edu.br.trace.entities.ApacheSolrJFieldEnum;
import splab.ufcg.edu.br.trace.entities.TraceLink;
import splab.ufcg.edu.br.trace.entities.TraceLinkList;
import splab.ufcg.edu.br.trace.exceptions.IndexException;
import splab.ufcg.edu.br.trace.interfaces.Indexable;
import splab.ufcg.edu.br.trace.interfaces.Translatable;
import splab.ufcg.edu.br.trace.search.util.ConnectionProperties;
import splab.ufcg.edu.br.trace.search.util.ExecutionMode;
import splab.ufcg.edu.br.trace.search.util.IndexerProperties;
import splab.ufcg.edu.br.trace.writer.TraceLinkWriter;

public class ApacheSolrJIndexer implements Indexable {

	private static final String DELETE_ALL_INDEXES = "*:*";

	private static final long COMMIT_LOT_SIZE = 1000;

	private ConnectionProperties connectionProperties;

	private IndexerProperties indexerProperties;

	private Translatable traceLinkWriter;

	public ConnectionProperties getConnectionProperties() {
		return connectionProperties;
	}

	public void setConnectionProperties(
			ConnectionProperties connectionProperties) {
		this.connectionProperties = connectionProperties;
	}

	public IndexerProperties getIndexerProperties() {
		return indexerProperties;
	}

	public void setIndexerProperties(IndexerProperties indexerProperties) {
		this.indexerProperties = indexerProperties;
	}

	public Translatable getTraceLinkWriter() {
		return traceLinkWriter;
	}

	public void setTraceLinkWriter(Translatable traceLinkWriter) {
		this.traceLinkWriter = traceLinkWriter;
	}

	private TraceLinkList tracelinkList;

	public ApacheSolrJIndexer() {

	}

	public ApacheSolrJIndexer(IndexerProperties indexerProperties,
			ConnectionProperties apacheConnection) {

		this();
		this.indexerProperties = indexerProperties;
		this.connectionProperties = apacheConnection;
		
	}

	@Override
	public void indexTraceLinks(File directory) throws IndexException {

		if (indexerProperties == null || connectionProperties == null) {
			StringBuilder message = new StringBuilder();
			message.append("Cannot execute indexing operations without set up properties");
			message.append(System.lineSeparator());
			message.append("Indexer Properties: ");
			message.append(indexerProperties);
			message.append(System.lineSeparator());
			message.append("Connection Properties: ");
			message.append(connectionProperties);

			throw new IndexException(message.toString());
		}

		try {

			if (ExecutionMode.FULL.equals(indexerProperties.getMode())) {
				this.clearIndexDatabase();

				this.importTraceLinks(directory);

			} else {
				throw new IndexException("Not yet implemented");
			}

		} catch (SolrServerException ex) {

			StringBuilder message = new StringBuilder();
			message.append("Could not establish connection with Solr server: ");
			message.append(this.connectionProperties.getConnectionUrl());

			throw new IndexException(message.toString(), ex);

		} catch (Exception ex) {

			StringBuilder message = new StringBuilder();
			message.append("Unexpected error while indexing tracelinks: ");
			message.append(ex.getMessage());

			throw new IndexException(message.toString(), ex);
		}
	}

	private void importTraceLinks(File directory) throws Exception {

		

		if (directory.exists()) {

			File[] fileList = directory.listFiles();

			for (File file : fileList) {
				traceLinkWriter = new TraceLinkWriter();

				this.tracelinkList = traceLinkWriter.read(file);

				if (canIndex()) {
					this.indexImportedTraceLinks();
				}
			}

		} else {

			StringBuilder message = new StringBuilder();
			message.append("Could not find directory to import trace links: ");
			message.append(this.indexerProperties.getDirectory());

			throw new IndexException(message.toString());
		}

	}

	private void indexImportedTraceLinks() throws SolrServerException,
			Exception {

		HttpSolrServer server = new HttpSolrServer(
				this.connectionProperties.getConnectionUrl());

		long count = 0;

		for (TraceLink tracelink : this.tracelinkList.getTraceLinks()) {

			SolrInputDocument doc = this.getDocummentFromTraceLink(tracelink);

			if (count % COMMIT_LOT_SIZE == 0) {
				server.commit();
			}
			server.add(doc);
			count++;
		}

		server.commit();

	}

	private SolrInputDocument getDocummentFromTraceLink(TraceLink tracelink) {
		long currentID = SolrJID.getInstance().getNextId();
		SolrInputDocument doc = new SolrInputDocument();

		doc.addField(ApacheSolrJFieldEnum.ID.toString(), currentID);
		doc.addField(ApacheSolrJFieldEnum.REQUIREMENT.toString(),
				tracelink.getRequirement());
		doc.addField(ApacheSolrJFieldEnum.SEMANTIC.toString(),
				tracelink.getSemantic());
		doc.addField(ApacheSolrJFieldEnum.ARTIFACT_TYPE.toString(),
				tracelink.getArtifactType());
		doc.addField(ApacheSolrJFieldEnum.ARTIFACT.toString(),
				tracelink.getArtifact());

		return doc;
	}

	@Override
	public void clearIndexDatabase() throws IndexException {

		try {
			HttpSolrServer server = new HttpSolrServer(
					this.connectionProperties.getConnectionUrl());

			server.deleteByQuery(DELETE_ALL_INDEXES);

			server.commit();

		} catch (SolrServerException ex) {
			StringBuilder message = new StringBuilder();
			message.append("Could not establish connection with Solr server: ");
			message.append(this.connectionProperties.getConnectionUrl());

			throw new IndexException(message.toString(), ex);

		} catch (Exception ex) {

			StringBuilder message = new StringBuilder();
			message.append("Unexpected error while purging index database");

			throw new IndexException(message.toString(), ex);
		}
	}

	private boolean canIndex() {
		return tracelinkList != null & tracelinkList.getTraceLinks() != null
				&& tracelinkList.getTraceLinks().size() > 0;
	}

	public boolean isEmpty() throws IndexException {

		QueryResponse response;

		try {
			HttpSolrServer server = new HttpSolrServer(
					this.connectionProperties.getConnectionUrl());

			SolrQuery query = new SolrQuery();
			query.setQuery("*:*");
			query.setStart(0);
			query.set("defType", "edismax");
			response = server.query(query);
		} catch (SolrServerException ex) {
			StringBuilder message = new StringBuilder();
			message.append("Unexpected error while purging index database");

			throw new IndexException(message.toString(), ex);
		}
		SolrDocumentList results = response.getResults();

		return results.isEmpty();
	}

	


}
